package com.lxbw.chain.service;

import com.lxbw.chain.config.LxbwConfig;
import com.lxbw.chain.model.TokenCore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tx.ClientTransactionManager;
import org.web3j.tx.TransactionManager;
import rx.Observable;
import rx.Observer;

import java.math.BigInteger;
import java.util.concurrent.CompletableFuture;


@Service
public class TokenCoreService {
    public static final BigInteger GAS_PRICE = BigInteger.valueOf(20_000_000_000L);
    public static final BigInteger GAS_LIMIT = BigInteger.valueOf(6_300_000);

    @Autowired
    private LxbwConfig lxbwConfig;

    @Autowired
    private Web3j web3j;

    public String deploy(String tokenName, String tokenSymbol, BigInteger initialSupply, String fromAddr) throws Exception {
        TransactionManager txm = new ClientTransactionManager(web3j, fromAddr);

        CompletableFuture<TokenCore> async = TokenCore.deploy(web3j, txm, GAS_PRICE, GAS_LIMIT, tokenName, tokenSymbol, initialSupply).sendAsync();
        return async.join().getContractAddress();
    }

    public String name(String contractAddr) throws Exception {
        return loadForLookup(contractAddr).name().send();
    }

    public BigInteger balanceOf(String contractAddr, String address) throws Exception {
        return loadForLookup(contractAddr).balanceOf(address).send();
    }

    public String transfer(String contractAddr, String to, long val) throws Exception {
        TokenCore tokenCore = load(contractAddr, lxbwConfig.getFromAddress());
        TransactionReceipt tx = tokenCore.transfer(to, BigInteger.valueOf(val)).send();
        return tx.getTransactionHash();
    }

    public String allowance(String contractAddr, String owner, String spender) throws Exception {
        BigInteger send = loadForLookup(contractAddr).allowance(owner, spender).send();
        return send.toString();
    }

    public String transferFrom(String contractAddr, String from, String to, long val) throws Exception {
        TokenCore TokenCore = load(contractAddr, from);
        TransactionReceipt tx = TokenCore.transferFrom(from, to, BigInteger.valueOf(val)).send();
        return tx.getTransactionHash();
    }

    public String approve(String contractAddr,String owner, String spender, long val) throws Exception {
        TokenCore TokenCore = load(contractAddr, owner);
        TransactionReceipt tx = TokenCore.approve(spender, BigInteger.valueOf(val)).send();
        return tx.getTransactionHash();
    }


    private TokenCore loadForLookup(String contractAddr) {
        Credentials credentials = Credentials.create(lxbwConfig.getFromPrivatekey(), lxbwConfig.getFromAddress());
        return TokenCore.load(contractAddr, web3j, credentials, GAS_PRICE, GAS_LIMIT);
    }

    private TokenCore load(String contractAddr, String from) {
        TransactionManager txm = new ClientTransactionManager(web3j, from);
        return TokenCore.load(contractAddr, web3j, txm, GAS_PRICE, GAS_LIMIT);
    }

    public String issue(String contractAddr, String fromAddress, long val) throws Exception {
        return load(contractAddr, fromAddress).issue(BigInteger.valueOf(val)).send().getTransactionHash();
    }
}
